
            <!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>[k8s] 第一章 十分钟带你理解Kubernetes核心概念</title>
            </head>
            <body>
            <a href="https://andyoung.blog.csdn.net">原作者博客</a>
            <div id="content_views" class="markdown_views prism-atom-one-light">
                    <svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                        <path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path>
                    </svg>
                    <p>本章节主要介绍应用程序在服务器上部署方式演变以及kubernetes的概念、组件和工作原理。</p> 
<h3><a id="_3"></a>应用部署方式演变</h3> 
<p>在部署应用程序的方式上，主要经历了三个时代：</p> 
<ul><li> <p><strong>传统部署</strong>：互联网早期，会直接将应用程序部署在物理机上</p> 
  <blockquote> 
   <p>优点：简单，不需要其它技术的参与</p> 
   <p>缺点：不能为应用程序定义资源使用边界，很难合理地分配计算资源，而且程序之间容易产生影响</p> 
  </blockquote> </li><li> <p><strong>虚拟化部署</strong>：可以在一台物理机上运行多个虚拟机，每个虚拟机都是独立的一个环境</p> 
  <blockquote> 
   <p>优点：程序环境不会相互产生影响，提供了一定程度的安全性</p> 
   <p>缺点：增加了操作系统，浪费了部分资源</p> 
  </blockquote> </li><li> <p><strong>容器化部署</strong>：与虚拟化类似，但是共享了操作系统</p> 
  <blockquote> 
   <p>优点：</p> 
   <p>可以保证每个容器拥有自己的文件系统、CPU、内存、进程空间等</p> 
   <p>运行应用程序所需要的资源都被容器包装，并和底层基础架构解耦</p> 
   <p>容器化的应用程序可以跨云服务商、跨Linux操作系统发行版进行部署</p> 
  </blockquote> </li></ul> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/36aaca14af61206c8379f338ee5a61fe.png#pic_center" alt="image-20200505183738289"></p> 
<p>容器化部署方式给带来很多的便利，但是也会出现一些问题，比如说：</p> 
<ul><li>一个容器故障停机了，怎么样让另外一个容器立刻启动去替补停机的容器</li><li>当并发访问量变大的时候，怎么样做到横向扩展容器数量</li></ul> 
<p>这些容器管理的问题统称为<strong>容器编排</strong>问题，为了解决这些容器编排问题，就产生了一些容器编排的软件：</p> 
<ul><li><strong>Swarm</strong>：Docker自己的容器编排工具</li><li><strong>Mesos</strong>：Apache的一个资源统一管控的工具，需要和Marathon结合使用</li><li><strong>Kubernetes</strong>：Google开源的的容器编排工具</li></ul> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/4b069adaf8c38f0b9145302473ce6790.png#pic_center" alt="image-20210823234609529"></p> 
<h3><a id="kubernetes_46"></a>kubernetes简介</h3> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/01c43ca2b22bb46415734ffaec942b65.png#pic_center" alt="image-20210823234629917"></p> 
<p>​</p> 
<pre><code>kubernetes，是一个全新的基于容器技术的分布式架构领先方案，是谷歌严格保密十几年的秘密武器----Borg系统的一个开源版本，于2014年9月发布第一个版本，2015年7月发布第一个正式版本。

kubernetes的本质是**一组服务器集群**，它可以在集群的每个节点上运行特定的程序，来对节点中的容器进行管理。目的是实现资源管理的自动化，主要提供了如下的主要功能：
</code></pre> 
<ul><li><strong>服务发现和负载均衡</strong>：Kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器，如果进入容器的流量很大， Kubernetes 可以负载均衡并分配网络流量，从而使部署稳定。</li><li><strong>存储编排</strong>：Kubernetes 允许你自动挂载你选择的存储系统，例如本地存储、公共云提供商等。</li><li><strong>自动部署和回滚</strong>：你可以使用 Kubernetes 描述已部署容器的所需状态，它可以以受控的速率将实际状态 更改为期望状态。例如，你可以自动化 Kubernetes 来为你的部署创建新容器， 删除现有容器并将它们的所有资源用于新容器。</li><li><strong>自我修复</strong>：Kubernetes 重新启动失败的容器、替换容器、杀死不响应用户定义的 运行状况检查的容器，并且在准备好服务之前不将其通告给客户端。</li><li><strong>密钥与配置管理</strong>：Kubernetes 允许你存储和管理敏感信息，例如密码、OAuth 令牌和 ssh 密钥。 你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置，也无需在堆栈配置中暴露密钥。</li></ul> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/34f9652f092fad194303cd13205bb75f.png#pic_center" alt="image-20200526203726071"></p> 
<p>实际上，使用Kubernetes只需一个部署文件，使用一条命令就可以部署多层容器（前端，后台等）的完整集群：</p> 
<pre><code>kubectl create -f single-config-file.yaml
</code></pre> 
<p>kubectl是和Kubernetes API交互的命令行程序。现在介绍一些核心概念。</p> 
<h4><a id="_72"></a>小结一下</h4> 
<p><strong>Kubernetes</strong>是一个开源的容器管理平台，简称k8s，用于管理<strong>多个主机</strong>上的<strong>容器化应用</strong>程序 ，提供了应用程序的<strong>快速部署、扩缩容，升级和回滚的能力</strong>；利用service可以实现<strong>服务发现，负载均衡以及转发</strong>，通过ingress可以实现七层负载均衡等功能；<strong>Kubernetes</strong>这个名字源于希腊语，意思是舵手或飞行员，谷歌在2014年开放了Kubernetes项目，Kubernetes建立在谷歌十五年生产经验的基础上而对广大用户开放使用，目前社区活跃度也很高。对于初学者，上面概念比较难以理解，那么可以把他翻译成成如下几句话：</p> 
<pre><code>1.可以批量管理docker容器
2.可以对应用升级和回滚
3.可以实现七层和四层负载均衡
4.可以实现服务的自动发现
5.可以快速部署我们想要的应用
6.能够自动对当前的架构进行扩容和缩容等操作
</code></pre> 
<h3><a id="kuberneteshttpskubernetesiozhdocsconceptsoverviewcomponents_87"></a><a href="https://kubernetes.io/zh/docs/concepts/overview/components/" rel="nofollow">kubernetes组件</a></h3> 
<p>Kubernetes 遵循非常传统的客户端/服务端的架构模式，客户端可以通过 RESTful 接口或者直接使用 kubectl 与 Kubernetes 集群进行通信，这两者在实际上并没有太多的区别，后者也只是对 Kubernetes 提供的 RESTful API 进行封装并提供出来。每一个 Kubernetes 集群都是由一组 Master 节点和一系列的 Worker 节点组成，其中 Master 节点主要负责存储集群的状态并为 Kubernetes 对象分配和调度资源。<br> <img src="https://i-blog.csdnimg.cn/blog_migrate/56738fe9d248295566a5b929f97027e9.png#pic_center" alt=""><br> 一个kubernetes集群主要是由<strong>控制节点(master)</strong>、**工作节点(node)**构成，每个节点上都会安装不同的组件。</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/7a48203aeba8120cd7d4ccccdce69996.png" alt="在这里插入图片描述"></p> 
<h4><a id="__Master__95"></a>主节点服务 - Master 架构</h4> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/595286cb79f1950c1df738a8b202c0de.png#pic_center" alt=""><br> 作为管理集群状态的 Master 节点，它主要负责接收客户端的请求，安排容器的执行并且运行控制循环，将集群的状态向目标状态进行迁移。Master 节点内部由下面三个组件构成：</p> 
<p><strong>API Server</strong>: 负责处理来自用户的请求，其主要作用就是对外提供 RESTful 的接口，提供了资源操作的唯一入口，并提供认证、授权、访问控制、API注册和发现等机制，负责接收、解析、处理请求。。</p> 
<p><strong>etcd</strong>: etcd是一个key/value形式的键值存储，保存了整个kubernetes集群的状态，在kubernetes中使用etcd时，需要对etcd做备份，保证高可用，整个kubernetes系统中一共有两个服务需要用到etcd用来协同和存储配置，分别是：</p> 
<p>（1）网络插件calico，对于其它网络插件也需要用到etcd存储网络的配置信息</p> 
<p>（2）kubernetes本身，包括各种对象的状态和元信息配置</p> 
<blockquote> 
 <p>**注意：**网络插件操作etcd使用的是v2的API，而kubernetes操作etcd使用的v3的API，所以在下面我们执行etcdctl的时候需要设置ETCDCTL_API环境变量，该变量默认值为2，表示使用v2版本的api，v3表示使用v3版本的api</p> 
</blockquote> 
<p><strong>Scheduler</strong>: 调度器，负责资源的调度，按照预定的调度策略将Pod调度到相应的机器上。</p> 
<p><strong>kube-controller-manager</strong>: 控制器，负责维护集群的状态，检查pod的健康状态，比如故障检测、自动扩展、滚动更新等一些操作；</p> 
<h4><a id="__Node__114"></a>工作节点 - Node 架构</h4> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/d2d2760a15832c62ad2c998ee9ea0b9a.png#pic_center" alt=""><br> 其他的 Worker 节点实现就相对比较简单了，它主要由 kubelet 和 kube-proxy 两部分组成。</p> 
<p><strong>kubelet</strong>: 是工作节点执行操作的 agent，负责与master节点的apiserver进行通信的，接收到客户的请求，进行创建Pod，管理Pod，启动pod等相关操作(负责具体的容器生命周期管理)</p> 
<p><strong>kube-proxy</strong>: k8s代理，是在群集中的每个节点上运行的网络代理，kube-proxy负责请求转发，一旦发现了某一个Service关联的Pod信息发生了改变（如IP、Port等），由Kube-Proxy就会把变化后的service转换成IPVS或IPtables规则中，完成对后端pod的负载均衡</p> 
<p>Container Runtime: 容器运行环境是负责运行容器的软件，Kubernetes 支持多个容器运行环境: Docker、 containerd、cri-o、 rktlet 以及任何实现 Kubernetes CRI(容器运行环境接口)。</p> 
<h5><a id="_125"></a>主要由以下几个核心组件组成：</h5> 
<ul><li> <p>apiserver</p> 
  <ul><li>所有服务访问的唯一入口，提供认证、授权、访问控制、API 注册和发现等机制</li></ul> </li><li> <p>controller manager</p> 
  <ul><li>负责维护集群的状态，比如副本期望数量、故障检测、自动扩展、滚动更新等</li></ul> </li><li> <p>scheduler</p> 
  <ul><li>负责资源的调度，按照预定的调度策略将 Pod 调度到相应的机器上</li></ul> </li><li> <p>etcd</p> 
  <ul><li>键值对数据库，保存了整个集群的状态</li></ul> </li><li> <p>kubelet</p> 
  <ul><li>负责维护容器的生命周期，同时也负责 Volume 和网络的管理</li></ul> </li><li> <p>kube-proxy</p> 
  <ul><li>负责为 Service 提供 cluster 内部的服务发现和负载均衡</li></ul> </li><li> <p>Container runtime</p> 
  <ul><li>负责镜像管理以及 Pod 和容器的真正运行</li></ul> </li></ul> 
<p>除了核心组件，还有一些推荐的插件：</p> 
<ul><li> <p>CoreDNS</p> 
  <ul><li>可以为集群中的 SVC 创建一个域名 IP 的对应关系解析的 DNS 服务</li></ul> </li><li> <p>Dashboard</p> 
  <ul><li>给 K8s 集群提供了一个 B/S 架构的访问入口</li></ul> </li><li> <p>Ingress Controller</p> 
  <ul><li>官方只能够实现四层的网络代理，而 Ingress 可以实现七层的代理</li></ul> </li><li> <p>Prometheus</p> 
  <ul><li>给 K8s 集群提供资源监控的能力</li></ul> </li><li> <p>Federation</p> 
  <ul><li>提供一个可以跨集群中心多 K8s 的统一管理功能，提供跨可用区的集群</li></ul> </li></ul> 
<h4><a id="Pod_179"></a>Pod</h4> 
<p><a href="https://kubernetes.io/zh/docs/concepts/workloads/pods/" rel="nofollow">Pod</a>（上图绿色方框）安排在节点上，包含一组容器和卷。同一个Pod里的容器共享同一个网络命名空间，可以使用localhost互相通信。Pod是短暂的，不是持续性实体。你可能会有这些问题：</p> 
<ul><li>如果Pod是短暂的，那么我怎么才能持久化容器数据使其能够跨重启而存在呢？ 是的，Kubernetes支持<a href="https://kubernetes.io/zh/docs/concepts/workloads/pods/#pod-storage" rel="nofollow">卷</a>的概念，因此可以使用持久化的卷类型。</li><li>是否手动创建Pod，如果想要创建同一个容器的多份拷贝，需要一个个分别创建出来么？可以手动创建单个Pod，但是也可以使用Replication Controller使用Pod模板创建出多份拷贝，下文会详细介绍。</li><li>如果Pod是短暂的，那么重启时IP地址可能会改变，那么怎么才能从前端容器正确可靠地指向后台容器呢？这时可以使用Service，下文会详细介绍。</li></ul> 
<h4><a id="Lable_187"></a>Lable</h4> 
<p>正如图所示，一些Pod有Label。一个Label是attach到Pod的一对键/值对，用来传递用户定义的属性。比如，你可能创建了一个"tier"和“app”标签，通过Label（<strong>tier=frontend, app=myapp</strong>）来标记前端Pod容器，使用Label（<strong>tier=backend, app=myapp</strong>）标记后台Pod。然后可以使用<a href="" rel="nofollow">Selectors</a>选择带有特定Label的Pod，并且将Service或者Replication Controller应用到上面。</p> 
<h4><a id="Replication_Controller_191"></a>Replication Controller</h4> 
<p><em>是否手动创建Pod，如果想要创建同一个容器的多份拷贝，需要一个个分别创建出来么，能否将Pods划到逻辑组里？</em></p> 
<p>Replication Controller确保任意时间都有指定数量的Pod“副本”在运行。如果为某个Pod创建了Replication Controller并且指定3个副本，它会创建3个Pod，并且持续监控它们。如果某个Pod不响应，那么Replication Controller会替换它，保持总数为3.如下面的动画所示：</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/cd9323789b11256488dae13fa35ea516.png#pic_center" alt="Replication Controller"></p> 
<p>如果之前不响应的Pod恢复了，现在就有4个Pod了，那么Replication Controller会将其中一个终止保持总数为3。如果在运行中将副本总数改为5，Replication Controller会立刻启动2个新Pod，保证总数为5。还可以按照这样的方式缩小Pod，这个特性在执行滚动升级时很有用。</p> 
<p>当创建Replication Controller时，需要指定两个东西：</p> 
<ol><li>Pod模板：用来创建Pod副本的模板</li><li>Label：Replication Controller需要监控的Pod的标签。</li></ol> 
<p>现在已经创建了Pod的一些副本，那么在这些副本上如何均衡负载呢？我们需要的是Service。</p> 
<h4><a id="Service_210"></a>Service</h4> 
<p><em>如果Pods是短暂的，那么重启时IP地址可能会改变，怎么才能从前端容器正确可靠地指向后台容器呢？</em></p> 
<p>Service是定义一系列Pod以及访问这些Pod的策略的一层<strong>抽象</strong>。Service通过Label找到Pod组。因为Service是抽象的，所以在图表里通常看不到它们的存在，这也就让这一概念更难以理解。</p> 
<p>现在，假定有2个后台Pod，并且定义后台Service的名称为‘backend-service’，lable选择器为（<strong>tier=backend, app=myapp</strong>）。<em>backend-service</em> 的Service会完成如下两件重要的事情：</p> 
<ul><li>会为Service创建一个本地集群的DNS入口，因此前端Pod只需要DNS查找主机名为 ‘backend-service’，就能够解析出前端应用程序可用的IP地址。</li><li>现在前端已经得到了后台服务的IP地址，但是它应该访问2个后台Pod的哪一个呢？Service在这2个后台Pod之间提供透明的负载均衡，会将请求分发给其中的任意一个（如下面的动画所示）。通过每个Node上运行的代理（kube-proxy）完成。</li></ul> 
<blockquote> 
 <p>Endpoint是kubernetes中的一个资源对象，存储在etcd中，用来记录一个service对应的所有pod的访问地址，它是根据service配置文件中selector描述产生的,由 kube-proxy 负责将服务 IP 负载均衡到这些endpoints 上。每个 Service 都会自动分配一个 cluster IP（仅在集群内部可访问的虚拟地址）和 DNS 名，其他容器可以通过该地址或 DNS 来访问服务，而不需要了解后端容器的运行。<br> 一个Service由一组Pod组成，这些Pod通过Endpoints暴露出来，Endpoints是实现实际服务的端点集合。换句话说，service和pod之间的联系是通过endpoints实现的。<br> 每创建一个service，k8s会自动创建一个同名的 Endpoint出来 。</p> 
</blockquote> 
<p>下述动画展示了Service的功能。注意该图作了很多简化。如果不进入网络配置，那么达到透明的负载均衡目标所涉及的底层网络和路由相对先进。</p> 
<p><a href="http://dockone.io/uploads/article/20190625/e7a273fcdc03d2417b354b60c253552f.gif" rel="nofollow"><img src="https://i-blog.csdnimg.cn/blog_migrate/cb288afa019200d0fe54e9fbb8c244df.png#pic_center" alt="3.gif"></a></p> 
<p>有一个特别类型的Kubernetes Service，称为<code>LoadBalancer</code>，作为外部负载均衡器使用，在一定数量的Pod之间均衡流量。比如，对于负载均衡Web流量很有用。</p> 
<h4><a id="Node_237"></a>Node</h4> 
<p>节点（上图橘色方框）是物理或者虚拟机器，作为Kubernetes worker，通常称为Minion。每个节点都运行如下Kubernetes关键组件：</p> 
<ul><li>Kubelet：是主节点代理。</li><li>Kube-proxy：Service使用其将链接路由到Pod，如上文所述。</li><li>Docker或Rocket：Kubernetes使用的容器技术来创建容器。</li></ul> 
<h4><a id="Kubernetes_Master_247"></a>Kubernetes Master</h4> 
<p>集群拥有一个Kubernetes Master（紫色方框）。Kubernetes Master提供集群的独特视角，并且拥有一系列组件，比如Kubernetes API Server。API Server提供可以用来和集群交互的REST端点。master节点包括用来创建和复制Pod的Replication Controller。</p> 
<img src="https://gitee.com/andanyoung/blog-img/raw/master/img1/image-20200406184656917.png" alt="image-20200406184656917"> 
<p>下面，以部署一个nginx服务来说明kubernetes系统各个组件调用关系：</p> 
<ol><li> <p>首先要明确，一旦kubernetes环境启动之后，master和node都会将自身的信息存储到etcd数据库中</p> </li><li> <p>一个nginx服务的安装请求会首先被发送到master节点的apiServer组件</p> </li><li> <p>apiServer组件会调用scheduler组件来决定到底应该把这个服务安装到哪个node节点上</p> <p>在此时，它会从etcd中读取各个node节点的信息，然后按照一定的算法进行选择，并将结果告知apiServer</p> </li><li> <p>apiServer调用controller-manager去调度Node节点安装nginx服务</p> </li><li> <p>kubelet接收到指令后，会通知docker，然后由docker来启动一个nginx的pod</p> <p>pod是kubernetes的最小操作单元，容器必须跑在pod中至此，</p> </li><li> <p>一个nginx服务就运行了，如果需要访问nginx，就需要通过kube-proxy来对pod产生访问的代理</p> <pre><code>这样，外界用户就可以访问集群中的nginx服务了
</code></pre> </li></ol> 
<h3><a id="kubernetes_273"></a>kubernetes概念</h3> 
<p><strong>Master</strong>：集群控制节点，每个集群需要至少一个master节点负责集群的管控</p> 
<p><strong>Node</strong>：工作负载节点，由master分配容器到这些node工作节点上，然后node节点上的docker负责容器的运行</p> 
<p><strong>Pod</strong>：kubernetes的最小控制单元，容器都是运行在pod中的，一个pod中可以有1个或者多个容器</p> 
<p><strong>Controller</strong>：控制器，通过它来实现对pod的管理，比如启动pod、停止pod、伸缩pod的数量等等</p> 
<p><strong>Service</strong>：pod对外服务的统一入口，下面可以维护者同一类的多个pod</p> 
<p><strong>Label</strong>：标签，用于对pod进行分类，同一类pod会拥有相同的标签</p> 
<p><strong>NameSpace</strong>：命名空间，用来隔离pod的运行环境</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/cb6c57dfb1b296e74ed92696e6d911c6.png#pic_center" alt="image-20210823234700047"></p> 
<h3><a id="Kubernetes_291"></a><strong>Kubernetes架构</strong></h3> 
<p>k8s的物理结构是master/node模式,架构图如下所示：</p> 
<p><img src="https://i-blog.csdnimg.cn/blog_migrate/c807fdfe80136be566a0473271455a48.png#pic_center" alt="Kubernetes架构"></p> 
<p>master一般是三个节点或者五个节点做高可用，根据集群规模来定，master高可用指的是对apiserver做高可用或者对master的物理节点做高可用，node可以有多个节点，专门用来部署应用的。</p>
                </div>
            </body>
            </html>
            